---
title: Card field and Card form
description: Accept a payment with Cardfield and Cardform.
---

# Accept a payment - Cardfield / Cardform

You can use the Cardield and the Cardform if you want to embed CardPayments into your own screen. Both widgets offer less smooth out of the box experience and need more work than our recommended way for paying: [PaymentSheet](https://docs.page/flutter-stripe/flutter_stripe/sheet)

## 1. Set up Stripe [Server Side] [Client Side]

First, you need a Stripe account. [Register now](https://dashboard.stripe.com/register).

#### Server-side

This integration requires endpoints on your server that talk to the Stripe API. Use one official libraries for access to the Stripe API from your server. [Follow the steps here](https://stripe.com/docs/payments/accept-a-payment?platform=ios&ui=payment-sheet#setup-server-side)

#### Client-side

The Flutter SDK is open source, fully documented.

To install the SDK, follow these steps:
 - Run the commmand `flutter pub add flutter_stripe`
 - This will add a line like this to your project's pubspec.yaml with the latest package version


For details on the latest SDK release and past versions, see the [Releases](https://github.com/flutter-stripe/flutter_stripe/releases) page on GitHub. To receive notifications when a new release is published, [watch releases for the repository](https://docs.github.com/en/github/managing-subscriptions-and-notifications-on-github/managing-subscriptions-for-activity-on-github/viewing-your-subscriptions#watching-releases-for-a-repository).


When your app starts, configure the SDK with your Stripe [publishable key](https://dashboard.stripe.com/) so that it can make requests to the Stripe API. 

```dart
void main() async {
  Stripe.publishableKey = stripePublishableKey;
  runApp(const App());
}
```

Use your [test mode](https://stripe.com/docs/keys#obtain-api-keys) keys while you test and develop, and your [live mode](https://stripe.com/docs/keys#test-live-modes) keys when you publish your app.

## 2. Add an enpoint [Server Side]

First, you need a Stripe account. [Register now](https://dashboard.stripe.com/register).

#### Server-side

This integration uses three Stripe API objects:

1. A [PaymentIntent](https://stripe.com/docs/api/payment_intents). Stripe uses this to represent your intent to collect payment from a customer, tracking your charge attempts and payment state changes throughout the process.

2. A [Customer](https://stripe.com/docs/api/customers) (optional). To set up a card for future payments, it must be attached to a Customer. Create a Customer object when your customer creates an account with your business. If your customer is making a payment as a guest, you can create a Customer object before payment and associate it with your own internal representation of the customer’s account later.

3. A Customer Ephemeral Key (optional). Information on the Customer object is sensitive, and can’t be retrieved directly from an app. An Ephemeral Key grants the SDK temporary access to the Customer.

>> If you never save cards to a Customer and don’t allow returning Customers to reuse saved cards, you can omit the Customer and Customer Ephemeral Key objects from your integration.

For security reasons, your app can’t create these objects. Instead, add an endpoint on your server that:

1. Retrieves the Customer, or creates a new one.
2. Creates an Ephemeral Key for the Customer.
3. Creates a PaymentIntent, passing the Customer id.
4. Returns the Payment Intent’s [client secret](https://stripe.com/docs/api/payment_intents/object#payment_intent_object-client_secret), the Ephemeral Key’s secret, and the Customer’s id to your app.

Check examples implementations for your server [here](https://stripe.com/docs/payments/accept-a-payment?platform=ios#add-server-endpoint)

## 3. Integrate the Cardfield or Cardform [Client Side]

### 3a Cardfield 

In case you want to display the card entry fields in one line you can use the `Cardfield` widget. 

First you need to add the `Cardfield` widget to the `build` method of your screen.

```dart
CardField(
    onCardChanged: (card) {
        setState(() {
          _card = card;
        });
    },    
);
```

In this very basic example we set the `CardFieldInputDetails` to the new object that we get when the users changes the input in the cardfield. If you want more advanced control we recommend adding a `CardEditController`. See the [Api docs](https://pub.dev/documentation/stripe_platform_interface/latest/stripe_platform_interface/CardEditController-class.html) for all possibilities.

Ideally you want only to display the `Pay button` when the CardFieldInputDetails are completed:

```dart
if(_card?.complete ?? false)
  ElevatedButton(
    onPressed: _handlePayPress,
    child: Text('Pay'),
  )
```

Last but not least you need to confirm the payment when the payment is completed.
```dart
await Stripe.instance.confirmPayment(
      clientSecret['clientSecret'],
      PaymentMethodParams.card(
        paymentMethodData: PaymentMethodData(
          billingDetails: billingDetails,
        ),
        options: PaymentMethodOptions(
          setupFutureUsage:
              _saveCard == true ? PaymentIntentsFutureUsage.OffSession : null,
        ),
    ),
);
```

### 3b Cardform 

In case you want to display the card entry fields in multiple lines you can use the `Cardform` widget. 

First you need to add the `Cardfield` widget to the `build` method of your screen.

```dart
CardFormField(
   controller: controller,
)
```

In this very basic example we create a `CardFormEditController`and assign it to the `CardFormField` widget. The initialisation of the controller can be done like:

```dart
class _NoWebhookPaymentCardFormScreenState
    extends State<NoWebhookPaymentCardFormScreen> {
  final controller = CardFormEditController();

  @override
  void initState() {
    controller.addListener(update);
    super.initState();
  }

  void update() => setState(() {});
  @override
  void dispose() {
    controller.removeListener(update);
    controller.dispose();
    super.dispose();
}
```

Ideally you want only to display the `Pay button` when the user did input valid data.

```dart
if(controller.details.complete == true)
  ElevatedButton(
    onPressed: _handlePayPress,
    child: Text('Pay'),
  )
```

Last but not least you need to confirm the payment when the payment is completed.
```dart
await Stripe.instance.confirmPayment(
      clientSecret['clientSecret'],
      PaymentMethodParams.card(
        paymentMethodData: PaymentMethodData(
          billingDetails: billingDetails,
        ),
    ),
);
```

Unless your business model requires immediate payment (e.g., an on-demand service), don’t assume you have received payment at this point. Instead, inform the customer that you confirmed their order and notify them by email when you fulfill their order in the next step.

## 4.  Handle post-payment events

Stripe sends a [`payment_intent.succeeded`](https://stripe.com/docs/api/events/types#event_types-payment_intent.succeeded) event when the payment completes. Use the Dashboard, a custom webhook, or a partner solution to receive these events and run actions, like sending an order confirmation email to your customer, logging the sale in a database, or starting a shipping workflow.

Listen for these events rather than waiting on a callback from the client. On the client, the customer could close the browser window or quit the app before the callback executes. Setting up your integration to listen for asynchronous events also makes it easier to accept more payment methods in the future. Check out our [guide to payment methods](https://stripe.com/payments/payment-methods-guide) to see the differences between all supported payment methods.


## 5. Test the integration

Several test cards are available for you to use in test mode to make sure this integration is ready. Use them with any CVC, postal code, and future expiration date.

| NUMBER           | DESCRIPTION |
| ------ | ------- |
| 4242424242424242 |	Succeeds and immediately processes the payment. |
| 4000002500003155 |	Requires authentication. Stripe will trigger a modal asking for the customer to authenticate. |
| 4000000000009995 |	Always fails with a decline code of insufficient_funds. |

For the full list of test cards see the guide on [testing](https://stripe.com/docs/testing).

## 6. Customisation.

Both the `CardField` as the `CardFormField` have customisation options. We recommend checking out the Apidocs for an up to date list of functionalities. [Api Cardfield](https://pub.dev/documentation/flutter_stripe/latest/flutter_stripe/CardField-class.html)  [Api CardFormField](https://pub.dev/documentation/flutter_stripe/latest/flutter_stripe/CardFormField-class.html)
